
const ncname = '[a-zA-Z_][\\w\\-\\.]*'
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
const startTagOpen = new RegExp(`^<${qnameCapture}`);

const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);

const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;



function createAstElement(tagName, attrs, children) {
    return {
        tagName,
        attrs,
        type: 1,
        hasAttrs: typeof attrs === 'object' ? Object.keys(attrs).length > 0  : false,
        children
    }
}


const option =  {
    start(tagName, attrs, unary){

        var astEle = createAstElement(tagName, attrs, []);

        var cur = currentParent();

        if(cur){

            astEle.parent = cur;
            cur.children.push(astEle);
        }else{
            astEle.parent = undefined;
        }

        htmlStack.push(astEle);

        if(Object.keys(astTree).length == 0){
            // 说明是第一个开始元素-

            Object.assign(astTree, astEle);
        }
    },

    chart(text){

        var res = parseText(text);
        if(res){

            var cur = currentParent();

            cur.children.push({
                type: 2,
                express: res
            })
        }
        // console.log(text);
    },

    end(tagName){

        let cur = currentParent();
        if(cur.tagName === tagName){
            htmlPop();
        }else{
            //
            console.warn('有问题， 这个标签 ： '+ cur.tagName);

            throw new Error('有问题， 这个'+ cur.tagName+ '标签 没有闭合')
        }
    },

    comment(){

    }
}

function parseText(text){
    const tagRE = /\{\{((?:.|\n)+?)\}\}/g
    const tokens = []
    if (!tagRE.test(text)) {
        tokens.push(JSON.stringify(text))

    }else{
        let lastIndex = tagRE.lastIndex = 0
        let match, index
        while ((match = tagRE.exec(text))) {
            index = match.index
            // 先把 {{ 前边的文本添加到tokens中
            if (index > lastIndex) {
                tokens.push(JSON.stringify(text.slice(lastIndex, index)))
            }
            // 把变量改成`_s(x)`这样的形式也添加到数组中
            tokens.push(`_s(${match[1].trim().replace('&gt;', '>').replace('&lt;', '<')})`)

            // 设置lastIndex来保证下一轮循环时，正则表达式不再重复匹配已经解析过的文本
            lastIndex = index + match[0].length
        }

        // 当所有变量都处理完毕后，如果最后一个变量右边还有文本，就将文本添加到数组中
        if (lastIndex < text.length) {
            tokens.push(JSON.stringify(text.slice(lastIndex)))
        }
    }
    return tokens.join('+')
}


function generate(ast){
    var code = ast ? genElement(ast) : '_c("div")';

    return {
        render: `with(this){ return ${code}}`
    }
}


function genElement(ast){

    var data = ast.hasAttrs ? genData(ast) : undefined;

    var children = genChildren(ast);

    var code = `_c(
        "${ast.tagName}",
        ${data},
        ${children}
    )`

    return code

}

function genData(ast){
    var data = '{';

    for(let key in ast.attrs){
        // todo
        if(key.indexOf(':') == 0){
            var attr = key.replace(':','');

            data += `${attr} : ${ast.attrs[key]} ,`
        }
    }

    data.replace(/\,$/, '');

    data += '}';

    return data;
}


function genChildren(ast){
    var children = ast.children;

    if(children.length){
        return `[${children.map(c => genNode(c)).join(',')}]`
    }
}

function genNode(node){
    if(node.type === 1) {
        return genElement(node);
    }else{
        return genText(node);
    }
}

function genText(text){
    return `_v(${
        text.type == 2 ?
            text.express:
            text
        })`;
}

const htmlStack = [];
const astTree = Object.create(null);

function currentParent(){
    return htmlStack[htmlStack.length - 1];
}

function htmlPop(){
    return htmlStack.pop();
}

function compiler(html, options){

    while(html.length > 0){
        let start = html.match(startTagOpen);
        if(start) {
            // start
            let tagName = start[1];
            html = html.substring(start[0].length);

            let attrs = {}
            while(html.match(attribute)){
                let res = html.match(attribute);
                attrs[res[1]] = res[3];

                html = html.substring(res[0].length);
            }

            if(options.start){
                options.start(tagName, attrs, true);
            }

            html = html.substring(1).trim(); // 去掉开始标签最后一个 ">".

            continue;
        }

        // 闭合标签 处理

        const endTagMatch = html.match(endTag);
        if (endTagMatch) {
            html = html.substring(endTagMatch[0].length);

            if(options.end){
                options.end(endTagMatch[1]);
            }
            continue
        }
        // 截取 字符串
        let textEnd = html.indexOf('<');
        if(textEnd > 0){

            // 说明有内容
            let rest = html.slice(textEnd);
            let text = '';
            let next = textEnd;
            while( !startTagOpen.test(rest) &&
                !endTag.test(rest)
                ){
                next= rest.indexOf('<');
                if(next < 0) break;
                textEnd += next;
                rest = html.slice(textEnd);
            }

            text = html.slice(0, textEnd);
            html = html.substring(textEnd);
            if(options.chart){
                options.chart(text);
            }
            continue;
        }else{
            // 找不到任何< 说明都是 html的文本内容

            let text = html;

            html = '';
        }
    }

    var compiled = generate(astTree);

    return {
        render: new Function(compiled.render),
        staticRenderFns: []
    }
}

export function compileToFunction(template){

    let es = compiler(template, option);
    let {render} = es;

    let staticRenderFns = es.staticRenderFns.map(item => item );

    return  {
        render,
        staticRender : staticRenderFns
    }
}
